type EventHandler = (...data: any[]) => void;

export class EventEmitter {
  listeners = new Map<string, EventHandler[]>();

  on(event: string, handler: EventHandler) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)!.push(handler);
  }

  off(event: string, handler: EventHandler) {
    if (!this.listeners.has(event)) {
      return;
    }
    const handlers = this.listeners.get(event)!;
    const newHandlers = handlers.filter((_handler) => _handler !== handler);
    if (newHandlers.length === 0) {
      this.listeners.delete(event);
    } else {
      this.listeners.set(event, newHandlers);
    }
  }

  once(event: string, handler: EventHandler) {
    const _once: EventHandler = (...data) => {
      handler(...data);
      this.off(event, _once);
    };
    this.on(event, _once);
  }

  emit(event: string, ...data: any[]) {
    if (!this.listeners.has(event)) {
      return;
    }
    const handlers = this.listeners.get(event)!;
    handlers.forEach((handler) => handler(...data));
  }

  removeAll(event?: string) {
    if (typeof event === "undefined") {
      this.listeners = new Map();
    } else {
      this.listeners.delete(event);
    }
  }
}
